
#ifndef SX_PLOT_AXES_H
#define SX_PLOT_AXES_H

#include <sxMath.h>
#include <sxGraphicsObject.h>

namespace Sx {
namespace Graphics {
namespace Objects {

class PlotAxes : public GraphicsObject {
public:
	/* Default square PlotAxes */
	PlotAxes();

	/* Copy Constructor */
	PlotAxes(const PlotAxes& plot);

	/* 
	 * Creates a new square PlotAxes. The total size of the PlotAxes will be
	 * (tickCount * tickSpacing) for each axis.
	 *   tickCount - The number of ticks/grid lines
	 *   tickSpacing - The space between each set of ticks/grid lines
	 */
	PlotAxes(unsigned int tickCount, float tickSpacing);

	/* 
	 * Creates a new PlotAxes with a user specified number of ticks for each
	 * axis.
	 *   nxTickCount - The number of x ticks in the negative direction
	 *   pxTickCount - The number of x ticks in the positive direction
	 *   nyTickCount - The number of y ticks in the negative direction
	 *   pyTickCount - The number of y ticks in the positive direction
	 *   nzTickCount - The number of z ticks in the negative direction
	 *   pzTickCount - The number of z ticks in the positive direction
	 *   tickSpacing - The space between each set of ticks/grid lines
	 */
	PlotAxes(unsigned int nxTickCount, unsigned int pxTickCount, unsigned int nyTickCount, unsigned int pyTickCount, unsigned int nzTickCount, unsigned int pzTickCount, float tickSpacing);

	/* 
	 * Creates a new Plot Axes based on the provided dimensions.
	 */
	PlotAxes(const Eigen::Vector3i& min, const Eigen::Vector3i& max);

	virtual ~PlotAxes();

	/* Graphics Object Implementation */
	bool construct();
	void update(float dt);

	/* 
	 * Functions for altering the fixed length of this PlotAxes. If this
	 * PlotAxes was not set to fixed, it will be after any of these functions
	 * are called.
	 */
	void setFixedLengths(const Eigen::Vector3f& min, const Eigen::Vector3f& max);
	void setMinimumLengths(const Eigen::Vector3f& min);
	void setMaximumLengths(const Eigen::Vector3f& max);

	/* Set the extent of this PlotAxes by component. */
	void setMinimumX(float x);
	void setMinimumY(float y);
	void setMinimumZ(float z);
	void setMaximumX(float x);
	void setMaximumY(float y);
	void setMaximumZ(float z);

	/* 
	 * Sets the total spanned length of the axis. The minimum is set to 
	 * -(length / 2) and the maximum will be set to (length / 2).
	 */
	void setXLength(float length);
	void setYLength(float length);
	void setZLength(float length);

	/* 
	 * These functions set the extent of this PlotAxes by nTicks * tickSpacing.
	 * Therefore if one of these functions is used this PlotAxes will not be
	 * fixed (if it was a fixed AxisGrid it will be changed: fixed = false).
	 */
	void setXExtents(unsigned int nxTicks, unsigned int pxTicks, float tickSpacing);
	void setYExtents(unsigned int nyTicks, unsigned int pyTicks, float tickSpacing);
	void setZExtents(unsigned int nzTicks, unsigned int pzTicks, float tickSpacing);

	/* Sets the number of ticks in either the positive or negative direction. */
	void setXTicks(unsigned int ticks, bool positive);
	void setYTicks(unsigned int ticks, bool positive);
	void setZTicks(unsigned int ticks, bool positive);

	/* Sets the tick spacing */
	void setTickSpacing(float spacing);

	/* Sets the number of ticks that are shown between tick labels. */
	void setTickLabelInterval(unsigned int interval);

	/* 
	 * These functions will define the extent of this PlotAxes in both the
	 * negative and positive directions.
	 */
	void setXTicks(unsigned int ticks);
	void setYTicks(unsigned int ticks);
	void setZTicks(unsigned int ticks);

	/* Axis visibility. */
	void setAxisVisibility(Math::Axis axis, bool b);
	void setAxisXVisible(bool b);
	void setAxisYVisible(bool b);
	void setAxisZVisible(bool b);

	/* Quick functions for hiding and showing components. */
	void hideAxes();
	void hideTicks();
	void hideTickLabels();
	void hideGrid();
	void hideXAxis();
	void hideYAxis();
	void hideZAxis();
	void showAxes();
	void showTicks();
	void showTickLabels();
	void showGrid();
	void showXAxis();
	void showYAxis();
	void showZAxis();

	/* Toggles for the display of each axis. */
	void setDisplayX(bool b);
	void setDisplayY(bool b);
	void setDisplayZ(bool b);

	void setDisplayTicks(bool b);
	void setDisplayTickLabels(bool b);
	void setDisplayGrid(bool b);
	void setDisplayGrid(Math::AxisPlane plane, bool b);

	/* 
	 * Sets the number of ticks for the specified axis in either the positive
	 * or negative direction.
	 */
	unsigned int getXTicks(bool positive = true) const;
	unsigned int getYTicks(bool positive = true) const;
	unsigned int getZTicks(bool positive = true) const;

	Eigen::Vector3f getMinimumFixedLengths() const;
	Eigen::Vector3f getMaximumFixedLengths() const;

	float getTickSpacing() const;

	bool xAxisVisible() const;
	bool yAxisVisible() const;
	bool zAxisVisible() const;
	bool gridVisible(Math::AxisPlane plane) const;
	bool ticksVisible() const;
	bool tickLabelsVisible() const;

	unsigned int getXTotalTicks() const;
	unsigned int getYTotalTicks() const;
	unsigned int getZTotalTicks() const;
	unsigned int getTickLabelInterval() const;
	
	float getXLength(bool positive) const;
	float getYLength(bool positive) const;
	float getZLength(bool positive) const;
	float getXTotalLength() const;
	float getYTotalLength() const;
	float getZTotalLength() const;

	Eigen::Vector3f mouseTestPos;

protected:
	void initalize();

	/*
	 * Number of ticks down each axis. n represents negative ticks and p
	 * represents positive ticks. For example, 10 nx ticks and 10 px ticks
	 * means that there will be 20 ticks on the x axis.
	 */
	unsigned int nxTicks, pxTicks;
	unsigned int nyTicks, pyTicks;
	unsigned int nzTicks, pzTicks;

	/*
	 * Extents of this PlotAxes if it is fixed: min < 0.0 and max > 0.0
	 */
	Eigen::Vector3f min, max;

	/* Tick interval represents the distance between grid lines. */
	float tickSpacing;

	/* The visibility of each axis can be toggled. */
	bool displayX, displayY, displayZ;

	/* 
	 * Tick label visibility. This is also used to determine which ticks are
	 * considered major (can be emphasized in the rendering).
	 */
	bool displayTickLabels;
	
	/* Defines on what interval the tick labels will be displayed. */
	unsigned int tickLabelInterval;

	/* 
	 * The visibility of the tick marks representing the grids interval can
	 * be toggled.
	 */
	bool displayTicks;

	/* The visibility of the grid can be toggled. */
	bool displayGrid_XY;
	bool displayGrid_YZ;
	bool displayGrid_XZ;
};

}

}

}

#endif
